import Cesium, { Cartesian2, Cartesian3, Entity, HeightReference, Scene, ScreenSpaceEventHandler } from '../Ces/Cesium';
import DrawObject from './DrawObject';
import DrawConfig from './DrawConfig';

interface DrawHandlerOptions {
  WE: any; // Replace 'any' with the actual type of WE if available
  clampToGround?: boolean;
  [key: string]: any; // For other optional properties
}

class DrawHandler {
  private WE: any;
  private heightReference: HeightReference;
  private _pointEntity: Entity | undefined;
  private _currentPosition: Cartesian3 | undefined;
  private _currentScreenPosition: Cartesian2;
  private _drawObject: DrawObject;
  private _readyPromise: any//Cesium.Deferred;
  private _leftClickHandler: ScreenSpaceEventHandler | undefined;
  private _mouseMoveHandler: ScreenSpaceEventHandler | undefined;
  private _rightClickHandler: ScreenSpaceEventHandler | undefined;
  private _leftDoubleClickHandler: ScreenSpaceEventHandler | undefined;
  private _toolTip: any; // Replace 'any' with the actual type if available

  constructor(options: DrawHandlerOptions) {
    this.WE = options.WE;
    const clampToGround = options.clampToGround?? false

    this.heightReference = clampToGround
      ? Cesium.HeightReference.CLAMP_TO_GROUND
      : this.WE.heightReference;
    this._pointEntity = undefined;
    this._currentPosition = undefined;
    this._currentScreenPosition = new Cesium.Cartesian2();
    this._drawObject = this.WE.geometryManager.add(new DrawObject({
      ...options,
      clampToGround: this.heightReference === Cesium.HeightReference.CLAMP_TO_GROUND,
    }));
    this._readyPromise = Cesium.defer();
  }

  get positions(): Cartesian3[] {
    return this._drawObject.positions;
  }

  get readyPromise(): Promise<any> {
    return this._readyPromise.promise;
  }

  startDraw(): void {
    const scene = this.WE.viewer.scene;

    this.createLeftDoubleClickHandler(scene);
    this.createLeftClickHandler(scene);
    this.createMouseMoveHandler(scene);
    this.createRightClickHandler(scene);
  }

  pickPosition(screenPosition: Cartesian2, scene: Scene): Cartesian3 | undefined {
    if (this.heightReference === Cesium.HeightReference.NONE) {
      return scene.camera.pickEllipsoid(
        screenPosition,
        scene.globe.ellipsoid,
      );
    }
    const ray = scene.camera.getPickRay(screenPosition);

    return scene.globe.pick(ray, scene);
  }

  private createLeftClickHandler(scene: Scene): void {
    const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    handler.setInputAction((movement: { position: Cartesian2 }) => {
      const position = movement.position;

      if (!position.equals(this._currentScreenPosition)) {
        position.clone(this._currentScreenPosition);
        const cartesian = this.pickPosition(movement.position, scene);

        if (Cesium.defined(cartesian)) {
          if (this.positions.length >= this._drawObject.maxNumPonint) {
            this.finish();
          } else {
            this.positions.push(cartesian);
          }
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    this._leftClickHandler = handler;
  }

  private createMouseMoveHandler(scene: Scene): void {
    const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    handler.setInputAction((movement: { endPosition: Cartesian2 }) => {
      const cartesian = this.pickPosition(movement.endPosition, scene);

      this.updatePoint(cartesian, movement.endPosition);
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    this._mouseMoveHandler = handler;
  }

  private createRightClickHandler(scene: Scene): void {
    const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    handler.setInputAction(() => {
      this._drawObject.isConstant = false;
      this.positions.length = 0;
      this.finish();
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    this._rightClickHandler = handler;
  }

  private createLeftDoubleClickHandler(scene: Scene): void {
    const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);

    handler.setInputAction(() => {
      this.finish();
    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
    this._leftDoubleClickHandler = handler;
  }

  updatePoint(position: Cartesian3 | undefined, screenPos: Cartesian2): void {
    this._currentPosition = position;
    const gotPosition = Cesium.defined(position);

    if (gotPosition) {
      if (this.positions.length === 1) {
        this.positions.push(position);
      }
      if (this.positions.length > 1) {
        this.positions[this.positions.length - 1] = position;
      }
      this._drawObject.dirty = gotPosition;
    }

    if (DrawConfig.showToolTip) {
      if (!Cesium.defined(this._toolTip)) {
        this._toolTip = this.WE.earthPinCollection.getToolTip();
      }

      this._toolTip.visible = gotPosition;
      this._toolTip.position = position;
      this._toolTip.content = this._drawObject.getTips();
    }

    if (!Cesium.defined(this._pointEntity)) {
      const positionProperty = new Cesium.CallbackProperty(() => this._currentPosition, false);

      this._pointEntity = this.WE.viewer.entities.add({
        position: positionProperty,
        point: {
          color: Cesium.Color.fromCssColorString(DrawConfig.pointColor),
          pixelSize: DrawConfig.pointPixelSize,
          heightReference: this.heightReference,
          disableDepthTestDistance: Number.MAX_VALUE,
        },
      });
    }
    this._pointEntity.show = gotPosition;
  }

  finish(): void {
    this.destroyHandler();

    if (Cesium.defined(this._toolTip)) {
      this._toolTip.visible = false;
    }
    if (Cesium.defined(this._pointEntity)) {
      this.WE.viewer.entities.remove(this._pointEntity);
      this._pointEntity = undefined;
    }

    const positions = this.positions;

    if (positions.length > 1) {
      if (positions[positions.length - 2].equalsEpsilon(positions[positions.length - 1], 1e-6)) {
        positions.pop();
      }
      if (positions.length < this._drawObject.minNumPonint) {
        this._drawObject.isConstant = false;
        this._readyPromise.resolve(null);
      } else {
        const lifeObj = new DrawObject({
          type: this._drawObject.type,
        });
        lifeObj.rectangle = this._drawObject.rectangle;
        lifeObj.positions = this._drawObject.positions;
        this._readyPromise.resolve(lifeObj);
      }
    } else {
      this._readyPromise.resolve(null);
    }

    this.destroyDrawObject();
  }

  isDdestroyed(): boolean {
    return false;
  }

  private destroyHandler(): void {
    //@ts-ignore
    this._leftClickHandler = this._leftClickHandler && this._leftClickHandler.destroy();
    //@ts-ignore
    this._leftDoubleClickHandler = this._leftDoubleClickHandler && this._leftDoubleClickHandler.destroy();
    //@ts-ignore
    this._mouseMoveHandler = this._mouseMoveHandler && this._mouseMoveHandler.destroy();
    //@ts-ignore
    this._rightClickHandler = this._rightClickHandler && this._rightClickHandler.destroy();
  }

  private destroyDrawObject(): void {
    if (this._drawObject && !this._drawObject.isConstant) {
      this.WE.geometryManager.remove(this._drawObject);
    }
    this._drawObject = undefined;
  }

  destroy(): void {
    if (Cesium.defined(this._pointEntity)) {
      this.WE.viewer.entities.remove(this._pointEntity);
      this._pointEntity = undefined;
    }
    this.destroyHandler();
    this.destroyDrawObject();
  }
}

export default DrawHandler;
